﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Aribaccio
{
    /// <summary>
    /// 定义扩展数据表属性
    /// </summary>
    public static class ExtendDataTable
    {
        /// <summary>
        ///  DataTable 转换为 List 集合  
        /// </summary>
        /// <typeparam name="T">泛型数据类型</typeparam>
        /// <param name="argDataTable">DataTable</param>
        /// <returns>对象集合</returns>
        public static List<T> ToList<T>(this DataTable argDataTable) where T : new()
        {
            if (argDataTable == null || argDataTable.Rows.Count <= 0) { return default; }
            List<T> list = new List<T>();
            Type type = typeof(T);
            //获取泛型的属性
            PropertyInfo[] propertyInfos = type.GetProperties();
            //获取数据集的表头，以便于匹配
            List<DataColumn> listColumns = argDataTable.Columns.Cast<DataColumn>().ToList();
            T t;
            foreach (DataRow dr in argDataTable.Rows)
            {
                t = new T();
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    try
                    {
                        //查看是否存在对应的列名
                        DataColumn dColumn = listColumns.Find(name => name.ToString().ToUpper() == propertyInfo.Name.ToUpper());
                        if (dColumn != null && !Convert.IsDBNull(dr[dColumn.ColumnName]) && dr[dColumn.ColumnName] != null)
                        {
                            //赋值
                            if (dColumn.DataType == Type.GetType("System.Double"))
                            {
                                propertyInfo.SetValue(t, Convert.ToDouble(dr[dColumn.ColumnName]), null);
                            }
                            else if (dColumn.DataType == Type.GetType("System.Decimal"))
                            {
                                propertyInfo.SetValue(t, Convert.ToDecimal(dr[dColumn.ColumnName]), null);
                            }
                            else { propertyInfo.SetValue(t, dr[dColumn.ColumnName], null); }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(ex.Message, ex);
                    }
                }
                list.Add(t);
            }
            return list;
        }
        /// <summary>
        ///  DataTable 转换为类型对象
        /// </summary>
        /// <typeparam name="T">泛型数据类型</typeparam>
        /// <param name="argDataTable">DataTable</param>
        /// <returns>对象</returns>
        public static T ToModel<T>(this DataTable argDataTable) where T : new()
        {
            if (argDataTable == null || argDataTable.Rows.Count == 0) return default;
            Type type = typeof(T);
            PropertyInfo[] propertyInfos = type.GetProperties();  //获取泛型的属性
            List<DataColumn> listColumns = argDataTable.Columns.Cast<DataColumn>().ToList();  //获取数据集的表头，以便于匹配
            T t = new T();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                try
                {
                    DataColumn dColumn = listColumns.Find(name => name.ToString().ToUpper() == propertyInfo.Name.ToUpper());  //查看是否存在对应的列名
                    if (dColumn != null && !Convert.IsDBNull(argDataTable.Rows[0][dColumn.ColumnName]) && argDataTable.Rows[0][dColumn.ColumnName] != null)
                    {
                        if (dColumn.DataType == Type.GetType("System.Double"))
                        {
                            propertyInfo.SetValue(t, Convert.ToDecimal(argDataTable.Rows[0][dColumn.ColumnName]), null);  //赋值
                        }
                        else
                        {
                            propertyInfo.SetValue(t, argDataTable.Rows[0][dColumn.ColumnName], null);  //赋值
                        }
                    }
                }
                catch (Exception)
                {
                    return default;
                }
            }
            return t;
        }
        /// <summary>  
        /// 泛型对象集合 转化为 DataTable  
        /// </summary>  
        /// <typeparam name="T">泛型数据类型</typeparam>  
        /// <param name="argList">泛型对象集合</param>  
        /// <returns></returns>  
        public static DataTable ToDataTable<T>(this IEnumerable<T> argList)
        {
            //创建属性的集合  
            List<PropertyInfo> pList = new List<PropertyInfo>();
            //获得反射的入口  
            Type type = typeof(T);
            DataTable dt = new DataTable();
            //把所有的public属性加入到集合 并添加DataTable的列  
            Array.ForEach(type.GetProperties(), p => { pList.Add(p); dt.Columns.Add(p.Name, p.PropertyType); });
            foreach (var item in argList)
            {
                //创建一个DataRow实例  
                DataRow row = dt.NewRow();
                //给row 赋值  
                pList.ForEach(p => row[p.Name] = p.GetValue(item, null));
                //加入到DataTable  
                dt.Rows.Add(row);
            }
            return dt;
        }

        /// <summary>
        /// 根据string名称排序扩展(单字段)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="argSource">排序数据源</param>
        /// <param name="argSortName">排序名称</param>
        /// <param name="argSortDirection">排序方式 asc或desc</param>
        /// <returns></returns>
        public static IQueryable<T> DataSorting<T>(this IQueryable<T> argSource, string argSortName, string argSortDirection)
        {
            string sortingDir = string.Empty;
            if (argSortDirection.ToUpper().Trim() == "ASC") { sortingDir = "OrderBy"; }
            else if (argSortDirection.ToUpper().Trim() == "DESC") { sortingDir = "OrderByDescending"; }
            ParameterExpression param = Expression.Parameter(typeof(T), argSortName);
            PropertyInfo? pi = typeof(T).GetProperty(argSortName);
            Type[] types = new Type[2];
            types[0] = typeof(T);
            types[1] = pi.PropertyType;
            Expression expr = Expression.Call(typeof(Queryable), sortingDir, types, argSource.Expression, Expression.Lambda(Expression.Property(param, argSortName), param));
            IQueryable<T> query = argSource.AsQueryable().Provider.CreateQuery<T>(expr);
            return query;
        }
        /// <summary>
        ///  根据多个string名称排序扩展(多字段)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data">数据源</param>
        /// <param name="orderParams">排序类</param>
        /// <returns></returns>
        public static IQueryable<T> DataManySorting<T>(this IQueryable<T> data, params OrderParam[] orderParams) where T : class
        {
            var parameter = Expression.Parameter(typeof(T), "p");
            if (orderParams != null && orderParams.Length > 0)
            {
                for (int i = 0; i < orderParams.Length; i++)
                {
                    var property = typeof(T).GetProperty(orderParams[i].PropertyName);
                    if (property != null)
                    {
                        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                        var orderByExpr = Expression.Lambda(propertyAccess, parameter);
                        string methodName = i > 0 ?
                            orderParams[i].IsDesc ? "ThenByDescending" : "ThenBy"
                            : orderParams[i].IsDesc ? "OrderByDescending" : "OrderBy";
                        var resultExp = Expression.Call(
                            typeof(Queryable), methodName,
                            new Type[] { typeof(T), property.PropertyType },
                            data.Expression, Expression.Quote(orderByExpr)
                            );
                        data = data.Provider.CreateQuery<T>(resultExp);
                    }
                }
            }
            return data;
        }

    }
}
